package cc.rengu.oltp.service.realize.impl;

import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.dao.*;
import cc.rengu.oltp.service.common.dao.impl.*;
import cc.rengu.oltp.service.common.entity.*;
import cc.rengu.oltp.service.model.TxnInfo;
import cc.rengu.oltp.service.realize.CacheService;
import cc.rengu.oltp.utility.util.RedisUtil;
import cc.rengu.oltp.utility.util.StringUtil;
import cc.rengu.oltp.utility.util.XmlConfigUtil;
import cc.rengu.utility.log.RgLog;
import cc.rengu.utility.log.RgLogger;
import com.alibaba.fastjson.JSON;

import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by 王成 on 2020/2/14
 */
public class CacheServiceImpl implements CacheService {
    private final RgLogger rglog = RgLog.getLogger(this.getClass().getName());

    @Override
    public void reloadTransAuthInfo(String instId, String msgSrcId) throws Exception {
        /* Step1：加载渠道交易权限配置信息 */
        SrcTxnAuthCfgMapper srcTxnAuthCfgMapper = new SrcTxnAuthCfgMapperImpl();
        List<SrcTxnAuthCfg> srcTxnAuthCfgList = srcTxnAuthCfgMapper.selectSrcTxnAuthCfgInfo(instId, msgSrcId);
        /* Step2：刷新交易权限配置信息 */
        if (null != srcTxnAuthCfgList && !srcTxnAuthCfgList.isEmpty()) {
            String patterns = instId.trim() + (StringUtil.isEmptyOrNull(msgSrcId) ? "" : msgSrcId.trim());
            Map<String, String> keyValueMap = RedisUtil.hashGetAll(AppParamConstant.TXN_INFO_CACHE);
            List<String> txnInfoKeysList = new ArrayList<>();
            keyValueMap.forEach((key, value) -> {
                if (key.startsWith(patterns)) {
                    txnInfoKeysList.add(key);
                }
            });
            if (!txnInfoKeysList.isEmpty()) {
                for (String key : txnInfoKeysList) {
                    RedisUtil.hashDelete(AppParamConstant.TXN_INFO_CACHE, key);
                }
            }
            for (SrcTxnAuthCfg srcTxnAuthCfg : srcTxnAuthCfgList) {
                srcTxnAuthCfg.setTransChannelId(StringUtil.isEmptyOrNull(srcTxnAuthCfg.getTransChannelId()) ? "*" : srcTxnAuthCfg.getTransChannelId());
                String txnKey = srcTxnAuthCfg.getInstId().trim() + srcTxnAuthCfg.getMsgSrcId().trim() + srcTxnAuthCfg.getTransChannelId().trim() + srcTxnAuthCfg.getTxnNum().trim() + srcTxnAuthCfg.getBizType().trim();
                TxnInfo txnInfo = new TxnInfo();
                txnInfo.setTxnKey(txnKey);
                txnInfo.setSrcTxnAuthCfg(srcTxnAuthCfg);
                /* Step2.1：获取交易异常配置信息 */
                SrcTxnExcpCfgMapper srcTxnExcpCfgMapper = new SrcTxnExcpCfgMapperImpl();
                SrcTxnExcpCfg srcTxnExcpCfg = srcTxnExcpCfgMapper.selectSrcTxnExcpCfgByPrimaryKey(instId, srcTxnAuthCfg.getMsgSrcId(), srcTxnAuthCfg.getTxnNum(), srcTxnAuthCfg.getBizType());
                if (null != srcTxnExcpCfg) {
                    txnInfo.setSrcTxnExcpCfg(srcTxnExcpCfg);
                }
                /* Step2.2：获取交易码通道服务调用配置信息 */
                ChannelCallCfgMapper channelCallCfgMapper = new ChannelCallCfgMapperImpl();
                List<ChannelCallCfg> channelCallCfgList = channelCallCfgMapper.selectChannelCallCfgByTxnNum(srcTxnAuthCfg.getInstId(), srcTxnAuthCfg.getMsgSrcId(), srcTxnAuthCfg.getTransChannelId(), srcTxnAuthCfg.getTxnNum(), srcTxnAuthCfg.getBizType());
                if (null == channelCallCfgList || channelCallCfgList.isEmpty()) {
                    channelCallCfgList = channelCallCfgMapper.selectChannelCallCfgByTxnNum(srcTxnAuthCfg.getInstId(), srcTxnAuthCfg.getMsgSrcId(), "*", srcTxnAuthCfg.getTxnNum(), srcTxnAuthCfg.getBizType());
                }
                if (null != channelCallCfgList && !channelCallCfgList.isEmpty()) {
                    channelCallCfgList = channelCallCfgList.stream().sorted(Comparator.comparing(ChannelCallCfg::getCallIndex)).collect(Collectors.toList());
                    channelCallCfgList.forEach(item -> {
                        if (item.getSyncQueryRepeatTime() > 0){
                            item.setSyncQueryRepeatTime(item.getSyncQueryRepeatTime() * 1000);
                        }
                    });
                    txnInfo.setChannelCallCfgList(channelCallCfgList);
                }
                /* Step2.3：将渠道交易权限信息加载到缓存中 */
                rglog.info("刷新渠道交易权限配置信息到缓存：KEY<{}>,VALUE<{}>", txnKey, JSON.toJSONString(txnInfo));
                RedisUtil.hashSet(AppParamConstant.TXN_INFO_CACHE, txnKey, JSON.toJSONString(txnInfo));
                /* Step2.4：加载通道交易权限配置信息 */
                if (null != channelCallCfgList && !channelCallCfgList.isEmpty()) {
                    DstTxnAuthCfgMapper dstTxnAuthCfgMapper = new DstTxnAuthCfgMapperImpl();
                    for (ChannelCallCfg channelCallCfg : channelCallCfgList) {
                        List<DstTxnAuthCfg> dstTxnAuthCfgList = dstTxnAuthCfgMapper.selectDstTxnAuthCfgInfo(instId, channelCallCfg.getCallChannelId());
                        if (null != dstTxnAuthCfgList && !dstTxnAuthCfgList.isEmpty()) {
                            String patternKeys = channelCallCfg.getInstId().trim() + channelCallCfg.getCallChannelId().trim();
                            keyValueMap = RedisUtil.hashGetAll(AppParamConstant.CHANNEL_TXN_CACHE);
                            List<String> dstChannelTxnKeysList = new ArrayList<>();
                            keyValueMap.forEach((key, value) -> {
                                if (key.startsWith(patternKeys)) {
                                    dstChannelTxnKeysList.add(key);
                                }
                            });
                            if (!dstChannelTxnKeysList.isEmpty()) {
                                for (String key : dstChannelTxnKeysList) {
                                    RedisUtil.hashDelete(AppParamConstant.CHANNEL_TXN_CACHE, key);
                                }
                            }
                            for (DstTxnAuthCfg dstTxnAuthCfg : (dstTxnAuthCfgList.stream().distinct().collect(Collectors.toList()))) {
                                String key = dstTxnAuthCfg.getInstId().trim() + dstTxnAuthCfg.getMsgDstId().trim() + dstTxnAuthCfg.getChannelTxn().trim();
                                rglog.info("刷新通道交易权限配置信息到缓存：KEY<{}>,VALUE<{}>", key, JSON.toJSONString(dstTxnAuthCfg));
                                RedisUtil.hashSet(AppParamConstant.CHANNEL_TXN_CACHE, key, JSON.toJSONString(dstTxnAuthCfg));
                            }
                        }
                    }
                }
            }
        }
    }

    @Override
    public void reloadSrcChannelInfo(String instId, String channelId) throws Exception {
        /* Step1：加载交易渠道信息 */
        SrcChannelInfoMapper srcChannelInfoMapper = new SrcChannelInfoMapperImpl();
        List<SrcChannelInfo> srcChannelInfoList = srcChannelInfoMapper.selectSrcChannelInfoByInstId(instId);
        if (!srcChannelInfoList.isEmpty()) {
            if (null != channelId && !channelId.isEmpty()) {
                srcChannelInfoList = srcChannelInfoList.stream().filter(item -> item.getSrcChannelId().equals(channelId)).collect(Collectors.toList());
            }
            if (!srcChannelInfoList.isEmpty()) {
                String patterns = instId.trim() + (StringUtil.isEmptyOrNull(channelId) ? "" : channelId.trim());
                Map<String, String> keyValueMap = RedisUtil.hashGetAll(AppParamConstant.CHANNEL_ACQ_INFO_CACHE);
                List<String> srcChannelInfoKeysList = new ArrayList<>();
                keyValueMap.forEach((key, value) -> {
                    if (key.startsWith(patterns)) {
                        srcChannelInfoKeysList.add(key);
                    }
                });
                if (!srcChannelInfoKeysList.isEmpty()) {
                    for (String key : srcChannelInfoKeysList) {
                        RedisUtil.hashDelete(AppParamConstant.CHANNEL_ACQ_INFO_CACHE, key);
                    }
                }
                for (SrcChannelInfo srcChannelInfo : (srcChannelInfoList.stream().distinct().collect(Collectors.toList()))) {
                    String srcChannelInfoKey = srcChannelInfo.getInstId().trim() + srcChannelInfo.getSrcChannelId().trim() + srcChannelInfo.getTransChannelId().trim();
                    rglog.info("刷新交易渠道信息到缓存：KEY<{}>,VALUE<{}>", srcChannelInfoKey, JSON.toJSONString(srcChannelInfo));
                    RedisUtil.hashSet(AppParamConstant.CHANNEL_ACQ_INFO_CACHE, srcChannelInfoKey, JSON.toJSONString(srcChannelInfo));
                }
            }
        }
    }

    @Override
    public void reloadDstChannelInfo(String instId, String channelId) throws Exception {
        /* Step1：加载支付通道信息 */
        DstChannelInfoMapper dstChannelInfoMapper = new DstChannelInfoMapperImpl();
        List<DstChannelInfo> dstChannelInfoList = dstChannelInfoMapper.selectDstChannelInfoByInstId(instId);
        if (!dstChannelInfoList.isEmpty()) {
            if (null != channelId && !channelId.isEmpty()) {
                dstChannelInfoList = dstChannelInfoList.stream().filter(item -> item.getDstChannelId().equals(channelId)).collect(Collectors.toList());
            }
            if (!dstChannelInfoList.isEmpty()) {
                String patterns = instId.trim() + (StringUtil.isEmptyOrNull(channelId) ? "" : channelId.trim());
                Map<String, String> keyValueMap = RedisUtil.hashGetAll(AppParamConstant.CHANNEL_ISS_INFO_CACHE);
                List<String> dstChannelInfoKeysList = new ArrayList<>();
                keyValueMap.forEach((key, value) -> {
                    if (key.startsWith(patterns)) {
                        dstChannelInfoKeysList.add(key);
                    }
                });
                if (!dstChannelInfoKeysList.isEmpty()) {
                    for (String key : dstChannelInfoKeysList) {
                        RedisUtil.hashDelete(AppParamConstant.CHANNEL_ISS_INFO_CACHE, key);
                    }
                }
                for (DstChannelInfo dstChannelInfo : (dstChannelInfoList.stream().distinct().collect(Collectors.toList()))) {
                    String dstChannelInfoKey = dstChannelInfo.getInstId().trim() + dstChannelInfo.getDstChannelId().trim();
                    rglog.info("刷新支付通道信息到缓存：KEY<{}>,VALUE<{}>", dstChannelInfoKey, JSON.toJSONString(dstChannelInfo));
                    RedisUtil.hashSet(AppParamConstant.CHANNEL_ISS_INFO_CACHE, dstChannelInfoKey, JSON.toJSONString(dstChannelInfo));
                }
            }
            /*Step2：加载支付通道配置信息 */
            DstChannelCfgMapper dstChannelCfgMapper = new DstChannelCfgMapperImpl();
            List<DstChannelCfg> dstChannelCfgList = dstChannelCfgMapper.loadAllDstChannelCfg();
            if (!dstChannelCfgList.isEmpty()) {
                if (null != channelId && !channelId.isEmpty()) {
                    dstChannelCfgList = dstChannelCfgList.stream().filter(item -> item.getDstChannelId().equals(channelId)).collect(Collectors.toList());
                }
                if (!dstChannelCfgList.isEmpty()) {
                    String patterns = instId.trim() + (StringUtil.isEmptyOrNull(channelId) ? "" : channelId.trim());
                    Map<String, String> keyValueMap = RedisUtil.hashGetAll(AppParamConstant.CHANNEL_INFO_CFG_CACHE);
                    List<String> dstChannelCfgKeysList = new ArrayList<>();
                    keyValueMap.forEach((key, value) -> {
                        if (key.startsWith(patterns)) {
                            dstChannelCfgKeysList.add(key);
                        }
                    });
                    if (!dstChannelCfgKeysList.isEmpty()) {
                        for (String key : dstChannelCfgKeysList) {
                            RedisUtil.hashDelete(AppParamConstant.CHANNEL_INFO_CFG_CACHE, key);
                        }
                    }
                    for (DstChannelCfg dstChannelCfg : (dstChannelCfgList.stream().distinct().collect(Collectors.toList()))) {
                        String dstChannelCfgKey = dstChannelCfg.getInstId().trim() + dstChannelCfg.getDstChannelId().trim() + dstChannelCfg.getDstChannelType().trim();
                        rglog.info("刷新支付通道配置信息到缓存：KEY<{}>,VALUE<{}>", dstChannelCfgKey, JSON.toJSONString(dstChannelCfg));
                        RedisUtil.hashSet(AppParamConstant.CHANNEL_INFO_CFG_CACHE, dstChannelCfgKey, JSON.toJSONString(dstChannelCfg));
                    }
                }
            }
        }
    }

    @Override
    public void reloadDstChannelTxn(String instId, String msgDstId) throws Exception {
        DstTxnAuthCfgMapper dstTxnAuthCfgMapper = new DstTxnAuthCfgMapperImpl();
        List<DstTxnAuthCfg> dstTxnAuthCfgList = dstTxnAuthCfgMapper.selectDstTxnAuthCfgInfo(instId, msgDstId);
        /* Step1：加载渠道交易权限配置信息 */
        if (null != dstTxnAuthCfgList && !dstTxnAuthCfgList.isEmpty()) {
            String keys = instId.trim() + (StringUtil.isEmptyOrNull(msgDstId) ? "" : msgDstId.trim());
            Map<String, String> keyValueMap = RedisUtil.hashGetAll(AppParamConstant.CHANNEL_TXN_CACHE);
            List<String> dstChannelTxnKeysList = new ArrayList<>();
            keyValueMap.forEach((key, value) -> {
                if (key.startsWith(keys)) {
                    dstChannelTxnKeysList.add(key);
                }
            });
            if (!dstChannelTxnKeysList.isEmpty()) {
                for (String key : dstChannelTxnKeysList) {
                    RedisUtil.hashDelete(AppParamConstant.CHANNEL_TXN_CACHE, key);
                }
            }
            for (DstTxnAuthCfg dstTxnAuthCfg : (dstTxnAuthCfgList.stream().distinct().collect(Collectors.toList()))) {
                String key =dstTxnAuthCfg.getInstId().trim() + dstTxnAuthCfg.getMsgDstId().trim() + dstTxnAuthCfg.getChannelTxn().trim();
                rglog.info("刷新通道交易权限配置信息到缓存：KEY<{}>,VALUE<{}>", key, JSON.toJSONString(dstTxnAuthCfg));
                RedisUtil.hashSet(AppParamConstant.CHANNEL_TXN_CACHE, key, JSON.toJSONString(dstTxnAuthCfg));
            }
        }
    }

    @Override
    public void reloadCardBinInfo() throws Exception {
        String applicationConfigName = new File("").getCanonicalPath() + AppParamConstant.APPLICATION_CONFIG_FILE_NAME;
        Set<String> dbPoolCashNode = XmlConfigUtil.getDbCorporationInfo(applicationConfigName);
        List<BinInfo> binInfoList = new ArrayList<>();
        BinInfoMapper binInfoMapper = new BinInfoMapperImpl();
        binInfoMapper.loadAllCardBinInfo(dbPoolCashNode, binInfoList);
        if (!binInfoList.isEmpty()) {
            RedisUtil.onceDel(AppParamConstant.CARD_BIN_CACHE);
            /* Step1.1：按照卡BIN前6位进行分组 */
            Map<String, List<BinInfo>> binInfoMap = new HashMap<>();
            for (BinInfo binInfo : binInfoList) {
                String binInfoKey = AppParamConstant.BIN_CACHE_KEY;
                if (binInfo.getBinLen() >= 6) {
                    binInfoKey = binInfo.getBinNo().substring(0, 6);
                }
                if (!binInfoMap.isEmpty() && null != binInfoMap.get(binInfoKey)) {
                    binInfoMap.get(binInfoKey).add(binInfo);
                } else {
                    List<BinInfo> binInfos = new ArrayList<>();
                    binInfos.add(binInfo);
                    binInfoMap.put(binInfoKey, binInfos);
                }
            }
            for (String binInfoKey : binInfoMap.keySet()) {
                List<BinInfo> binInfoList1 = binInfoMap.get(binInfoKey);
                /* Step1.2：去掉重复项 */
                List<BinInfo> binInfoList2 = binInfoList1.stream().distinct().collect(Collectors.toList());
                /* Step1.3：按照卡BIN长度降序排序 */
                List<BinInfo> binInfoList3 = binInfoList2.stream().sorted(Comparator.comparing(BinInfo::getBinLen)).collect(Collectors.toList());
                Collections.reverse(binInfoList3);
                /* Step1.4：将卡BIN信息加载到缓存 */
                RedisUtil.hashSet(AppParamConstant.CARD_BIN_CACHE, binInfoKey, JSON.toJSONString(binInfoList3));
            }
        }
    }

    @Override
    public void reloadSysParamInfo(String instId, String paramType) throws Exception {
        SysParamMapper sysParamMapper = new SysParamMapperImpl();
        List<SysParam> sysParamList = sysParamMapper.selectSysParamByInstIdAndParamType(instId, paramType);
        if (!sysParamList.isEmpty()) {
            /* Step1.1：去掉重复项 */
            List<SysParam> sysParamLists = sysParamList.stream().distinct().collect(Collectors.toList());
            sysParamLists = sysParamLists.stream().filter(item -> item.getParamStatus().equals(AppParamConstant.YES)).collect(Collectors.toList());
            /* Step1.2：按照法人行及参数类型进行整合 */
            Map<String, List<SysParam>> sysParamMap = new HashMap<>();
            for (SysParam sysParam : sysParamLists) {
                String sysParamKey = sysParam.getInstId().trim() + sysParam.getParamType().trim();
                List<SysParam> mapKeyValue = sysParamMap.get(sysParamKey);
                if (null != mapKeyValue && !mapKeyValue.isEmpty()) {
                    mapKeyValue.add(sysParam);
                    sysParamMap.put(sysParamKey, mapKeyValue);
                } else {
                    List<SysParam> sysParams = new ArrayList<>();
                    sysParams.add(sysParam);
                    sysParamMap.put(sysParamKey, sysParams);
                }
            }
            /* Step1.3：将系统参数加载到缓存 */
            String patterns = instId.trim() + (StringUtil.isEmptyOrNull(paramType) ? "" : paramType.trim());
            Map<String, String> keyValueMap = RedisUtil.hashGetAll(AppParamConstant.SYS_PARAM_CACHE);
            List<String> sysParamKeysList = new ArrayList<>();
            keyValueMap.forEach((key, value) -> {
                if (key.startsWith(patterns)) {
                    sysParamKeysList.add(key);
                }
            });
            if (!sysParamKeysList.isEmpty()) {
                for (String key : sysParamKeysList) {
                    RedisUtil.hashDelete(AppParamConstant.SYS_PARAM_CACHE, key);
                }
            }
            for (String key : sysParamMap.keySet()) {
                rglog.info("刷新系统参数信息到缓存：KEY<{}>,VALUE<{}>", key, JSON.toJSONString(sysParamMap.get(key)));
                RedisUtil.hashSet(AppParamConstant.SYS_PARAM_CACHE, key, JSON.toJSONString(sysParamMap.get(key)));
            }
        }
    }

    @Override
    public void reloadRspCodeMapInfo(String instId) throws Exception {
        RspCodeMapMapper rspCodeMapMapper = new RspCodeMapMapperImpl();
        List<RspCodeMap> rspCodeMapList = rspCodeMapMapper.selectRespCodeMapInfoByInstId(instId);
        if (!rspCodeMapList.isEmpty()) {
            String patterns = instId.trim();
            Map<String, String> keyValueMap = RedisUtil.hashGetAll(AppParamConstant.RSP_CODE_MAP_CACHE);
            List<String> rspCodeMapKeysList = new ArrayList<>();
            keyValueMap.forEach((key, value) -> {
                if (key.startsWith(patterns)) {
                    rspCodeMapKeysList.add(key);
                }
            });
            if (!rspCodeMapKeysList.isEmpty()) {
                for (String key : rspCodeMapKeysList) {
                    RedisUtil.hashDelete(AppParamConstant.RSP_CODE_MAP_CACHE, key);
                }
            }
            rspCodeMapList = rspCodeMapList.stream().distinct().collect(Collectors.toList());
            Map<String, List<RspCodeMap>> rspCodeMaps = new HashMap<>();
            for (RspCodeMap rspCodeMap : rspCodeMapList) {
                String rspCodeMapkey = rspCodeMap.getInstId().trim() + rspCodeMap.getSrcSysId().trim() + rspCodeMap.getSrcRspCode().trim();
                if (!rspCodeMaps.isEmpty() && null != rspCodeMaps.get(rspCodeMapkey)) {
                    rspCodeMaps.get(rspCodeMapkey).add(rspCodeMap);
                } else {
                    List<RspCodeMap> rspCodeMapTmpList = new ArrayList<>();
                    rspCodeMapTmpList.add(rspCodeMap);
                    rspCodeMaps.put(rspCodeMapkey, rspCodeMapTmpList);
                }
            }
            for (String rspCodeMapKey : rspCodeMaps.keySet()) {
                List<RspCodeMap> rspCodeMapsTmp = rspCodeMaps.get(rspCodeMapKey);
                rglog.info("映射码转换关系配置KEY:<{}>,VALUE:<{}>", rspCodeMapKey, JSON.toJSONString(rspCodeMapsTmp));
                RedisUtil.hashSet(AppParamConstant.RSP_CODE_MAP_CACHE, rspCodeMapKey, JSON.toJSONString(rspCodeMapsTmp));
            }
        }
    }
}
